
#include "mopplink.h"

char *md5(char *buffer2, int dataLength) {
    char *decrypt = (char *)calloc(16, sizeof(char));
    MD5_CTX md5;
    MD5_Init(&md5);
    MD5_Update(&md5, buffer2, dataLength);
    MD5_Final(decrypt, &md5);
    return decrypt;
}

Encrypt sm2Encrypt(char *data, char *key_path) {
    BIO *bio = BIO_new_file(key_path, "r");
    EVP_PKEY *publickKey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
    EVP_PKEY_set_alias_type(publickKey, EVP_PKEY_SM2);

    EVP_PKEY_CTX *pkey_ctx = EVP_PKEY_CTX_new(publickKey, NULL);
    EVP_PKEY_encrypt_init(pkey_ctx);

    char *out = NULL;
    out = (char *)calloc(300, sizeof(char));
    int cipher_len;
    int err = EVP_PKEY_encrypt(pkey_ctx, NULL, &cipher_len, data, strlen(data));
    printf("err is %d %d\n", err, cipher_len);
    if (err <= 0) {
        printf("err code is %d\n", err);
        Encrypt encrypt;
        encrypt.len = 0;
        encrypt.data = NULL;
        return encrypt;
    }

    char *out2 = (char *)calloc(cipher_len + 5, sizeof(char));
    err = EVP_PKEY_encrypt(pkey_ctx, out2, &cipher_len, data, strlen(data));
    // printf("err2 is %d %d\n %s\n", err, cipher_len, out2);
    EVP_PKEY_CTX_free(pkey_ctx);

    Encrypt encrypt;
    encrypt.len = cipher_len;
    encrypt.data = out2;

    free(out);
    BIO_free(bio);
    return encrypt;
}

Encrypt sm4Encryption(char *desPassword, char *data, int length) {
    size_t plainLen = length;
    size_t cipherLen = plainLen + 16 - plainLen % 16 + 100;

    EVP_CIPHER_CTX *cipher_ctx = EVP_CIPHER_CTX_new();
    char *sm4Key = calloc(16, sizeof(char));
    char *iVec = calloc(16, sizeof(char));
    memcpy(sm4Key, desPassword, 16);
    memcpy(iVec, desPassword + 16, 16);
    EVP_EncryptInit_ex(cipher_ctx, EVP_sm4_cbc(), NULL, sm4Key, iVec);
    EVP_CIPHER_CTX_set_padding(cipher_ctx, EVP_PADDING_PKCS7);

    int update_len;
    char *cipher = calloc(cipherLen, sizeof(char));
    if (!EVP_EncryptUpdate(cipher_ctx, cipher, &update_len, data, length)) {
        // NSLog(@"error:EVP_EncryptUpdate出错");
        printf("EVP_EncryptUpdate出错\n");
        Encrypt encrypt;
        encrypt.len = 0;
        encrypt.data = NULL;
        return encrypt;
    }

    int final_len;
    if (!EVP_EncryptFinal_ex(cipher_ctx, cipher + update_len, &final_len)) {
        Encrypt encrypt;
        encrypt.len = 0;
        encrypt.data = NULL;
        return encrypt;
    }

    Encrypt encrypt;
    encrypt.len = update_len + final_len;
    encrypt.data = cipher;

    EVP_CIPHER_CTX_free(cipher_ctx);
    free(sm4Key);
    free(iVec);
    return encrypt;
}

Encrypt sm4Decryption(char *desPassword, char *data, int length) {
    EVP_CIPHER_CTX *cipher_ctx = EVP_CIPHER_CTX_new();
    char *sm4Key = calloc(16, sizeof(char));
    char *iVec = calloc(16, sizeof(char));
    memcpy(sm4Key, desPassword, 16);
    memcpy(iVec, desPassword + 16, 16);

    EVP_DecryptInit_ex(cipher_ctx, EVP_sm4_cbc(), NULL, sm4Key, iVec);
    EVP_CIPHER_CTX_set_padding(cipher_ctx, EVP_PADDING_PKCS7);

    int update_len;
    char *plain = calloc(length, sizeof(char));
    if (!EVP_DecryptUpdate(cipher_ctx, plain, &update_len, data, length)) {
        printf("error:EVP_DecryptUpdate\n");
        Encrypt encrypt;
        encrypt.len = 0;
        encrypt.data = NULL;
        return encrypt;
    }

    int final_len;
    if (!EVP_DecryptFinal_ex(cipher_ctx, plain + update_len, &final_len)) {
        printf("error:EVP_DecryptFinal_ex\n");
        Encrypt encrypt;
        encrypt.len = 0;
        encrypt.data = NULL;
        return encrypt;
    }
    Encrypt encrypt;
    encrypt.len = update_len + final_len;
    encrypt.data = plain;
    EVP_CIPHER_CTX_free(cipher_ctx);
    free(sm4Key);
    free(iVec);
    return encrypt;
}

char *sm3(char *data, int length) {
    char *result = calloc(16, sizeof(char));
    char *out = calloc(32, sizeof(char));
    int out_size;
    EVP_Digest(data, length, out, &out_size, EVP_sm3(), NULL);
    for (int i = 0; i < 16; ++i) {
        result[i] = (out[i] ^ out[i + 16]);
    }
    return result;
}

void onMsgArrived(int sq, char *data) {
    cJSON *root = NULL;
    cJSON *body = NULL; // cjson对象
    cJSON *result = NULL;
    cJSON *timeCost = NULL;
    cJSON *user = NULL;
    cJSON *session = NULL;

    root = cJSON_Parse(data);
    if (!root) {
        printf("Error before: [%s]\n", cJSON_GetErrorPtr());
    }
    else {
        // printf("%s\n", "有格式的方式打印Json:");
        // printf("%s\n\n", cJSON_Print(root));
        result = cJSON_GetObjectItem(root, "result"); //
        if (result) {
            // printf("result %s\n", cJSON_Print(result), result->valuestring);
            if (strcmp("success", result->valuestring) == 0) {
                //服务端请求没毛病
                body = cJSON_GetObjectItem(root, "body"); //
                if (!body) {
                    //
                }
                timeCost = cJSON_GetObjectItem(root, "timeCost"); //
                if (timeCost) {
                    printf("this request server pod time cost is %dms\n", timeCost->valueint);
                }
                user = cJSON_GetObjectItem(root, "user"); //
                if (user) {
                    printf("get user info, value is %s\n", user->valuestring);
                }
                session = cJSON_GetObjectItem(root, "session"); //
                if (session) {
                    printf("get session, value is %s\n", user->valuestring);
                }
            }
            else {
                printf("服务端有毛病，返回的result不是success,是%s\n", result->valuestring);
            }
        }
        else {
            //显然，服务器端出毛病了
            printf("服务端有毛病，没有返回result字段\n");
        }
    }

    //释放内存
    if (root) {
        cJSON_free(root);
    }
    if (body) {
        cJSON_free(body);
    }
    if (result) {
        cJSON_free(result);
    }
    if (timeCost) {
        cJSON_free(timeCost);
    }
    if (user) {
        cJSON_free(user);
    }
    if (session) {
        cJSON_free(session);
    }
}
void onRequestTimeout(int sq) {
    printf("\n喵的，服务器响应超时了。sq is %d\n\n", sq);
}

void onMopplinkError(int errorCode, char *errorData) {
    printf("\n喵的，mopplink程序挂了。onMopplinkError;\ncode:%d;\n%s\n\n", errorCode, errorData);
}

int t-main(int argc) {
    int userGM = 1;
    printf("我要开始工作啦！\n");
    MopplinkCore core = {
        .heartBeatTime = 20,
        .timeout = 30,
        .onMsgArrived = onMsgArrived,
        .onTimeout = onRequestTimeout,
        .onError = onMopplinkError,
    };

    if (userGM) {
        printf("国密环境\n");
        core.isGM = 1;
        core.ip = "114.215.129.230";
        core.port = 6063;
        core.asymmetricEncryption = sm2Encrypt;
        core.symmetricEncryption = sm4Encryption;
        core.symmetricDecryption = sm4Decryption;
        core.digest = sm3;
        core.keyPath = "ppserver-test.sm2.pub.key";
    }
    else {
        printf("非国密环境\n");
        core.isGM = 0;
        core.ip = "114.215.129.230";
        core.port = 6033;
        core.asymmetricEncryption = rsaEncrypt;
        core.symmetricEncryption = desEncrypt;
        core.symmetricDecryption = desDecrypt;
        core.digest = md5;
        core.keyPath = "test_pub.key";
    }
    moppStart(core); //阻塞
}
